#include "FileManager.h"
#include <QDir>
#include <QFileInfo>
#include <QDebug>
#include <algorithm>
#include <QSet>
#include <QJsonDocument>
#include <QJsonArray>
#include <QFile>

FileManager& FileManager::getInstance()
{
    static FileManager instance;
    return instance;
}

FileManager::FileManager(QObject *parent) : QObject(parent) {}

void FileManager::scanDirectory(const QString &path) {
    m_files.clear();
    scanDirectoryRecursively(path);
    qDebug() << "Scanned" << m_files.size() << "files (images and videos only)";
}

void FileManager::scanDirectoryRecursively(const QString &path) {
    QDir dir(path);
    QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);

    for (const QFileInfo &fileInfo : fileList) {
        if (fileInfo.isDir()) {
            scanDirectoryRecursively(fileInfo.filePath());
        } else {
            FileInfo info = getFileInfo(fileInfo.filePath());
            if (info.fileType == FileType::Image) { // 只添加图片文件
                m_files.append(info);
            }
        }
    }
}

FileInfo FileManager::getFileInfo(const QString &filePath) {
    FileInfo info;
    QFileInfo fileInfo(filePath);

    info.fileName = fileInfo.fileName();
    info.filePath = fileInfo.filePath();
    info.fileSize = fileInfo.size();

    QString ext = fileInfo.suffix().toLower();
    if (QStringList{"jpg", "jpeg", "png", "gif"}.contains(ext)) {
        info.fileType = FileType::Image;
    } else if (QStringList{"mp4", "avi", "mov"}.contains(ext)) {
        info.fileType = FileType::Video;
    } else {
        info.fileType = FileType::Other;
        return info;  // 如果不是图片或视频，直接返回，不会被添加到 m_files
    }

    info.contentType = "其他"; // 默认内容类型
    info.contentDescription = "文件路径:" + info.filePath; // 默认值为"文件路径"加上info.filePath
    info.contentEmbedding = QVector<float>(10, 0.0f);

    // 重新设置人名为未知
    info.peopleNames.clear();
    info.peopleNames.append("未知");

    return info;
}

QList<FileInfo> FileManager::getSortedBySize() const {
    QList<FileInfo> sorted = m_files;
    std::sort(sorted.begin(), sorted.end(), [](const FileInfo &a, const FileInfo &b) {
        return a.fileSize > b.fileSize;
    });
    return sorted;
}

QList<FileInfo> FileManager::filterByContentType(const QString &type) const {
    QList<FileInfo> filtered;
    QStringList searchTypes = type.split(" ", Qt::SkipEmptyParts);
    
    for (const FileInfo &info : m_files) {
        QStringList fileTypes = info.contentType.split(" ", Qt::SkipEmptyParts);
        
        bool match = false;
        for (const QString &searchType : searchTypes) {
            QString trimmedSearchType = searchType.trimmed();
            for (const QString &fileType : fileTypes) {
                if (fileType.trimmed().contains(trimmedSearchType, Qt::CaseInsensitive)) {
                    match = true;
                    break;
                }
            }
            if (match) break;
        }
        
        if (match) {
            filtered.append(info);
        }
    }
    return filtered;
}

QList<FileInfo> FileManager::filterByPerson(const QString &personNames) const {
    QList<FileInfo> filtered;
    QStringList searchNames = personNames.split(" ", Qt::SkipEmptyParts);
    
    for (const FileInfo &info : m_files) {
        bool nameFound = false;
        for (const QString &searchName : searchNames) {
            for (const QString &name : info.peopleNames) {
                if (name.contains(searchName, Qt::CaseInsensitive)) {
                    nameFound = true;
                    break;
                }
            }
            if (nameFound) break;
        }
        if (nameFound) {
            filtered.append(info);
        }
    }
    return filtered;
}

QList<FileInfo> FileManager::filterByFileName(const QString &fileName) const {
    QList<FileInfo> filtered;
    for (const FileInfo &info : m_files) {
        if (info.fileName.contains(fileName, Qt::CaseInsensitive)) {
            filtered.append(info);
        }
    }
    return filtered;
}

QList<FileInfo> FileManager::filterByFileType(FileType type) const {
    QList<FileInfo> filtered;
    for (const FileInfo &info : m_files) {
        if (info.fileType == type) {
            filtered.append(info);
        }
    }
    return filtered;
}

QList<FileInfo> FileManager::getNewFiles(const QList<FileInfo> &oldFiles) const {
    QList<FileInfo> newFiles;
    QSet<QString> oldFilePaths;
    for (const FileInfo &info : oldFiles) {
        oldFilePaths.insert(info.filePath);
    }
    for (const FileInfo &info : m_files) {
        if (!oldFilePaths.contains(info.filePath)) {
            newFiles.append(info);
        }
    }
    return newFiles;
}

QList<FileInfo> FileManager::getMissingFiles(const QList<FileInfo> &oldFiles) const {
    QList<FileInfo> missingFiles;
    QSet<QString> currentFilePaths;
    for (const FileInfo &info : m_files) {
        currentFilePaths.insert(info.filePath);
    }
    for (const FileInfo &info : oldFiles) {
        if (!currentFilePaths.contains(info.filePath)) {
            missingFiles.append(info);
        }
    }
    return missingFiles;
}

void FileManager::saveToJson(const QString &filePath) const {
    QJsonArray jsonArray;
    for (const FileInfo &info : m_files) {
        jsonArray.append(fileInfoToJson(info));
    }

    QJsonDocument doc(jsonArray);
    QFile file(filePath);
    if (file.open(QIODevice::WriteOnly)) {
        file.write(doc.toJson());
        file.close();
        qDebug() << "File information saved to" << filePath;
    } else {
        qDebug() << "Failed to save file information to" << filePath;
    }
}

void FileManager::loadFromJson(const QString &filePath) {
    QFile file(filePath);
    if (file.open(QIODevice::ReadOnly)) {
        QByteArray data = file.readAll();
        file.close();

        QJsonDocument doc = QJsonDocument::fromJson(data);
        if (doc.isArray()) {
            m_files.clear();
            QJsonArray jsonArray = doc.array();
            for (const QJsonValue &value : jsonArray) {
                if (value.isObject()) {
                    m_files.append(jsonToFileInfo(value.toObject()));
                }
            }
            qDebug() << "Loaded" << m_files.size() << "files from" << filePath;
        }
    } else {
        qDebug() << "Failed to load file information from" << filePath;
    }
}

QJsonObject FileManager::fileInfoToJson(const FileInfo &info) const {
    QJsonObject json;
    json["fileName"] = info.fileName;
    json["filePath"] = info.filePath;
    json["fileSize"] = QString::number(info.fileSize);
    json["fileType"] = static_cast<int>(info.fileType);
    json["contentType"] = info.contentType;
    json["contentDescription"] = info.contentDescription;
    
    QJsonArray embeddingArray;
    for (float value : info.contentEmbedding) {
        embeddingArray.append(value);
    }
    json["contentEmbedding"] = embeddingArray;

    QJsonArray peopleNamesArray;
    for (const QString &name : info.peopleNames) {
        peopleNamesArray.append(name);
    }
    json["peopleNames"] = peopleNamesArray;

    return json;
}

FileInfo FileManager::jsonToFileInfo(const QJsonObject &json) const {
    FileInfo info;
    info.fileName = json["fileName"].toString();
    info.filePath = json["filePath"].toString();
    info.fileSize = json["fileSize"].toString().toLongLong();
    info.fileType = static_cast<FileType>(json["fileType"].toInt());
    info.contentType = json["contentType"].toString();
    info.contentDescription = json["contentDescription"].toString();

    QJsonArray embeddingArray = json["contentEmbedding"].toArray();
    info.contentEmbedding.clear();
    for (const QJsonValue &value : embeddingArray) {
        info.contentEmbedding.append(value.toDouble());
    }

    QJsonArray peopleNamesArray = json["peopleNames"].toArray();
    info.peopleNames.clear();
    for (const QJsonValue &value : peopleNamesArray) {
        info.peopleNames.append(value.toString());
    }

    return info;
}

// 更新peopleNames
void FileManager::updatePeopleNamesFromFaceRecognition(const QString &faceRecognitionFilePath) {
    QFile file(faceRecognitionFilePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qDebug() << "Failed to open face recognition results file:" << faceRecognitionFilePath;
        return;
    }

    QByteArray jsonData = file.readAll();
    file.close();

    QJsonDocument doc = QJsonDocument::fromJson(jsonData);
    if (!doc.isArray()) {
        qDebug() << "ERROR:人脸识别结果文件格式无效";
        return;
    }

    QJsonArray faceRecognitionArray = doc.array();
    QMap<QString, QStringList> faceRecognitionMap;

    // 解析face_recognition_results.json文件
    for (const QJsonValue &value : faceRecognitionArray) {
        QJsonObject obj = value.toObject();
        QString filePath = obj["filePath"].toString();
        QJsonArray peopleArray = obj["peopleNames"].toArray();
        QStringList peopleNames;
        for (const QJsonValue &personValue : peopleArray) {
            peopleNames.append(personValue.toString());
        }
        faceRecognitionMap[filePath] = peopleNames;
    }

    // 更新m_files中的peopleNames
    bool hasChanges = false;
    for (FileInfo &info : m_files) {
        if (faceRecognitionMap.contains(info.filePath)) {
            QStringList newPeopleNames = faceRecognitionMap[info.filePath];
            if (info.peopleNames != newPeopleNames) {
                info.peopleNames = newPeopleNames;
                qDebug() << "更新文件" << info.filePath<< "peopleNames:" << info.peopleNames;
                hasChanges = true;
            }
        }
    }

    // 如果有变动，保存到file_info.json
    if (hasChanges) {
        saveToJson("file_info.json");
        qDebug() << "Updated peopleNames and saved to file_info.json";
    } else {
        qDebug() << "No changes in peopleNames";
    }
}

QList<FileInfo>& FileManager::getFiles() {
    return m_files;
}

void FileManager::updateFileInfo(const QString &filePath, const QString &contentType, const QString &contentDescription, const QVector<float> &contentEmbedding)
{
    for (FileInfo &info : m_files) {
        if (info.filePath == filePath) {
            info.contentType = contentType;
            info.contentDescription = contentDescription;
            info.contentEmbedding = contentEmbedding;
            qDebug() << "Updated file info for:" << filePath;
            return;
        }
    }
    qDebug() << "File not found:" << filePath;
}

QStringList FileManager::getPeopleNamesFromFaceRecognition(const QString &jsonFilePath, const QString &imagePath)
{
    QStringList peopleNames;
    QFile file(jsonFilePath);
    if (!file.open(QIODevice::ReadOnly)) {
        qWarning() << "无法打开文件:" << jsonFilePath;
        return peopleNames;
    }

    QByteArray jsonData = file.readAll();
    QJsonDocument doc = QJsonDocument::fromJson(jsonData);
    QJsonArray jsonArray = doc.array();

    for (const QJsonValue &value : jsonArray) {
        QJsonObject obj = value.toObject();
        if (obj["filePath"].toString() == imagePath) {
            QJsonArray peopleArray = obj["peopleNames"].toArray();
            for (const QJsonValue &personValue : peopleArray) {
                peopleNames.append(personValue.toString());
            }
            break;  // 找到匹配的文件后就退出循环
        }
    }

    return peopleNames;
}
